package rmi.controller;

import hbt.dao.ClienteDAO;
import hbt.dao.CotizacionDAO;
import hbt.dao.FacturaDAO;
import hbt.dao.GeneralDAO;
import hbt.dao.ProveedorDAO;
import hbt.dao.RemitoDAO;
import hbt.dao.RodamientoDAO;
import hbt.dao.SolicitudCotizacionDAO;
import interfaz.TDAManejoDatos;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Date;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import negocio.Cliente;
import negocio.CondicionOperacion;
import negocio.Cotizacion;
import negocio.Factura;
import negocio.ItemCotizacion;
import negocio.ItemLista;
import negocio.ListaDePrecios;
import negocio.ODV;
import negocio.OrdenPedido;
import negocio.PorcentajeGanancia;
import negocio.Proveedor;
import negocio.Remito;
import negocio.Rodamiento;
import negocio.RodamientoID;
import negocio.SolicitudCotizacion;
import negocio.SolicitudCotizacionComponente;
import transformer.BeanTransformer;
import util.FechaUtil;
import Enum.EEstadoEntidad;
import beans.ComparativaBean;
import beans.CondicionOperacionBean;
import beans.CotizacionBean;
import beans.EntidadBean;
import beans.FacturaBean;
import beans.ItemComparativaBean;
import beans.ListaDePreciosBean;
import beans.OrdenDePedidoBean;
import beans.RodamientoBean;
import beans.SolicitudCotizacionBean;

public class RMIController extends UnicastRemoteObject implements
		TDAManejoDatos {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	final float porcentajeDeGanancia = 0.5f;

	public RMIController() throws RemoteException {
		super();
	}

	public List<ComparativaBean> obtenerComparativaPorMarca() throws Exception {
		List<ComparativaBean> ret = new LinkedList<ComparativaBean>();
		List<ItemLista> items = GeneralDAO.findAll(ItemLista.class);
		Map<String, ComparativaBean> mapa = new HashMap<String, ComparativaBean>();
		for (ItemLista i : items) {
			// segun el criterio guardo en el
			String codigo = i.getRodamiento().getMarca();
			ComparativaBean comparativa = mapa.get(codigo);
			if (comparativa == null) {
				comparativa = new ComparativaBean();
				comparativa.setMarca(i.getRodamiento().getMarca());
			}
			comparativa.getItemsLista().add(i.getItemComparativaBean());
			mapa.put(codigo, comparativa);
		}
		return new LinkedList(mapa.values());
	}

	public List<ComparativaBean> obtenerComparativaPorRodamiento()
			throws Exception {
		List<ComparativaBean> ret = new LinkedList<ComparativaBean>();
		List<ItemLista> items = GeneralDAO.findAll(ItemLista.class);
		Map<String, ComparativaBean> mapa = new HashMap<String, ComparativaBean>();
		for (ItemLista i : items) {
			// segun el criterio guardo en el
			String codigo = i.getRodamiento().getNroSerie() + "-"
					+ i.getRodamiento().getSufijo();
			ComparativaBean comparativa = mapa.get(codigo);
			if (comparativa == null) {
				comparativa = new ComparativaBean();
				comparativa.setNroRodamiento(i.getRodamiento().getNroSerie());
				comparativa.setSufijoRodamiento(i.getRodamiento().getSufijo());
				comparativa.setMarca(i.getRodamiento().getMarca());
				// comparativa.setOrigen(i.getRodamiento().getOrigen());
			}
			comparativa.getItemsLista().add(i.getItemComparativaBean());
			mapa.put(codigo, comparativa);
		}
		return new LinkedList(mapa.values());
	}

	public List<ComparativaBean> obtenerComparativaPorNroSerie()
			throws Exception {
		List<ComparativaBean> ret = new LinkedList<ComparativaBean>();
		List<ItemLista> items = GeneralDAO.findAll(ItemLista.class);
		Map<String, ComparativaBean> mapa = new HashMap<String, ComparativaBean>();
		for (ItemLista i : items) {
			// segun el criterio guardo en el
			String codigo = i.getRodamiento().getNroSerie();
			ComparativaBean comparativa = mapa.get(codigo);
			if (comparativa == null) {
				comparativa = new ComparativaBean();
				comparativa.setNroRodamiento(i.getRodamiento().getNroSerie());
			}
			comparativa.getItemsLista().add(i.getItemComparativaBean());
			mapa.put(codigo, comparativa);
		}
		return new LinkedList(mapa.values());
	}

	@Override
	public List<RodamientoBean> getRodamientosValidos() throws Exception {
		List<RodamientoBean> validos = new LinkedList<RodamientoBean>();
		RodamientoDAO dao = (RodamientoDAO) RodamientoDAO.getInstancia();

		for (Rodamiento r : dao.findAll()) {
			validos.add(r.getBean());
		}
		return validos;
	}

	@Override
	public boolean existeClienteByCuil(String cuitCliente) throws Exception {
		if (ClienteDAO.getInstancia().findById(cuitCliente) != null)
			return true;

		return false;
	}

	@Override
	public SolicitudCotizacionBean crearSolicitudCotizacion(SolicitudCotizacionBean solicitud, int sucursal)
			throws Exception {
		ODV odv = (ODV) GeneralDAO.getInstancia().findById(ODV.class, sucursal);
		Date fecha = FechaUtil.getSqlDateFromString(solicitud.getFecha());
		if(solicitud.getNumero() == null){
			solicitud.setNumero(getSiguienteNroSolicitud());
		}
		SolicitudCotizacion sc = new SolicitudCotizacion(solicitud.getNumero(),
				fecha, buscarClienteByCuil(solicitud.getCliente().getCuil()));
		for (RodamientoBean r : solicitud.getRodamientos()) {
			sc.generarSolicitudCotizacionComponente(
					buscarRodamientoById(new RodamientoID(r.getSerie(), r
							.getSufijo())), r.getCantidad());
		}
		
		sc.setOdv(odv);
		SolicitudCotizacionDAO.getInstancia().registrar(sc);
		solicitud.setNumero(sc.getNroSolicitud());
		return solicitud;

	}

	private Integer getSiguienteNroSolicitud() {
		//Implementar
		return new Random().nextInt();
	}

	public void crearListaDePrecio(ListaDePreciosBean lista) throws Exception {

		ListaDePrecios nueva = new ListaDePrecios(lista);
		Proveedor p = ProveedorDAO.getInstancia().findById(
				lista.getProveedor().getCuil());
		p.getCondiciones().clear();
		GeneralDAO.getInstancia().update(p);
		for (CondicionOperacionBean c : lista.getCondiciones()) {
			p.getCondiciones().add(CondicionOperacion.getCondicionFromBean(c));
		}
		GeneralDAO.getInstancia().update(p);
		ListaDePrecios listaAReemplazar = null;
		for (ListaDePrecios l : p.getListasDePrecio()) {
			if (l.getTipo().equals(lista.getTipo())) {
				listaAReemplazar = l;
				break;
			}
		}
		if (listaAReemplazar != null) {
			p.getListasDePrecio().remove(listaAReemplazar);
			// GeneralDAO.getInstancia().delete(listaAReemplazar);
		}

		ProveedorDAO.getInstancia().update(p);
		// GeneralDAO.getInstancia().registrar(nueva);
		p.getListasDePrecio().add(nueva);

		ProveedorDAO.getInstancia().update(p);

	}

	@Override
	public CotizacionBean generarCotiacion(SolicitudCotizacionBean s)
			throws Exception {
		Cotizacion c = new Cotizacion();
		c.setFecha(new Date(Calendar.getInstance().getTimeInMillis()));
		c.setVigencia(30);
		c.setCliente(buscarClienteByCuil(s.getCliente().getCuil()));
		c.setSolicitudCotizacion(SolicitudCotizacionDAO.getInstancia()
				.findById(s.getNumero()));
		List<ComparativaBean> comparativas = obtenerComparativaPorRodamiento();
		List<ComparativaBean> comparativasNroSerie = obtenerComparativaPorNroSerie();
		for (RodamientoBean bean : s.getRodamientos()) {
			boolean encontrado = false;
			for (ComparativaBean comp : comparativas) {
				if (comp.getNroRodamiento().equals(bean.getSerie())
						&& comp.getSufijoRodamiento().equals(bean.getSufijo())) {
					ItemCotizacion item = new ItemCotizacion();
					ItemComparativaBean icb = comp.getMejorPrecio();
					item.setProveedor(ProveedorDAO.getInstancia().findById(
							icb.getLista().getProveedor().getCuil()));
					item.setImporte(calcularPrecio(icb.getPrecio(),
							item.getProveedor()));
					c.getItemsCotizacion().add(item);
					item.setRodamientoComponente(new SolicitudCotizacionComponente(
							RodamientoDAO.getInstancia().findByNroYSufijo(
									icb.getRodamiento().getSerie(),
									icb.getRodamiento().getSufijo()), bean
									.getCantidad()));
					encontrado = true;
					break;
				}
			}
			if (!encontrado) {
				for (ComparativaBean comp : comparativasNroSerie) {
					if (comp.getNroRodamiento().equals(bean.getSerie())
							&& comp.getSufijoRodamiento().equals(
									bean.getSufijo())) {
						ItemCotizacion item = new ItemCotizacion();
						ItemComparativaBean icb = comp.getMejorPrecio();
						item.setProveedor(ProveedorDAO.getInstancia().findById(
								icb.getLista().getProveedor().getCuil()));
						item.setImporte(calcularPrecio(icb.getPrecio(),
								item.getProveedor()));
						c.getItemsCotizacion().add(item);
						item.setRodamientoComponente(new SolicitudCotizacionComponente(
								RodamientoDAO.getInstancia().findByNroYSufijo(
										icb.getRodamiento().getSerie(),
										icb.getRodamiento().getSufijo()), bean
										.getCantidad()));
						break;
					}
				}
			}
		}

		GeneralDAO.getInstancia().registrar(c);

		return c.getBean();

	}

	private float calcularPrecio(float precio, Proveedor proveedor) {
		float sumatoria = 0f;
		for (CondicionOperacion c : proveedor.getCondiciones()) {
			sumatoria += c.obtenerValorDeVenta(precio);
		}
		if (proveedor.getCondiciones().size() > 0)
			// saco un precio intermedio segun las condiciones.
			return obtenerPorcentajeGanancia().calcularPrecioVenta(
					sumatoria / proveedor.getCondiciones().size());

		return 0;
	}

	public Cliente buscarClienteByCuil(String cuil) throws Exception {
		return (Cliente) ClienteDAO.getInstancia().findById(cuil);
	}

	public Rodamiento buscarRodamientoById(RodamientoID id) throws Exception {
		return (Rodamiento) RodamientoDAO.getInstancia().findById(id);
	}

	public void registrarOrdenDePedido(OrdenDePedidoBean opb, int sucursal)
			throws Exception {
		ODV odv = (ODV) GeneralDAO.getInstancia().findById(ODV.class, sucursal);

		OrdenPedido op = BeanTransformer.toOrdenPedido(opb);

		odv.getOrdenesDePedidos().add(op);
		op.setOdv(odv);
		GeneralDAO.getInstancia().update(odv);

		new LocalController().generarOrdenesDeCompra();

	}

	public PorcentajeGanancia obtenerPorcentajeGanancia() {
		PorcentajeGanancia ret = GeneralDAO.getInstancia()
				.findPorcentajeGananciaVigente();
		if (ret == null) {
			ret = PorcentajeGanancia.getPorcentajeDefault();
		}
		return ret;
	}

	@Override
	public void altaCliente(EntidadBean eb) throws Exception {
		Cliente c = BeanTransformer.toCliente(eb);
		c.setEstado(EEstadoEntidad.activo);	
		ClienteDAO.getInstancia().registrar(c);
	}
	
	@Override
	public void altaProveedor(EntidadBean eb) throws Exception {
		Proveedor c = BeanTransformer.toProveedor(eb);
		c.setEstado(EEstadoEntidad.activo);	
		ProveedorDAO.getInstancia().registrar(c);
	}

	public List<FacturaBean> generarFacturas(int odv) throws Exception {
		List<Remito> pendientes = RemitoDAO.getInstancia()
				.findRemitosPendientesByODV(odv);
		List<FacturaBean> beans = new LinkedList<FacturaBean>();

		List<Factura> facturas = new LinkedList<Factura>();
		for (Remito r : pendientes) {
			Factura f = new Factura();
			f.setCliente(r.getCliente());
			f.setCondicionesVenta(new HashSet(r.getCliente().getCondiciones()));
			f.setFechaEmision(FechaUtil.getHoy());
			f.setRemito(r);
			f.setFechaVencimiento(FechaUtil.agregarDias(f.getFechaEmision(), 30));
			facturas.add(f);
		}

		FacturaDAO.getInstancia().registrarFacturas(facturas);
		for (Factura f : facturas) {
			beans.add(BeanTransformer.toFacturaBean(f));
		}

		return beans;
	}

	@Override
	public EntidadBean buscarCliente(String cuil) throws Exception {
		return ClienteDAO.getInstancia().findById(cuil).getBean();
	}

	@Override
	public EntidadBean buscarProveedor(String cuil) throws Exception {
		return ProveedorDAO.getInstancia().findById(cuil).getBean();
	}

	@Override
	public List<EntidadBean> getClientesActivos() throws Exception {
		List<EntidadBean> ebl = new LinkedList<EntidadBean>();
		List<Cliente> cl = ClienteDAO.getInstancia().findClientesActivos();
		for (Cliente c : cl) {
			ebl.add(c.getBean());
		}
		return ebl;
	}
	
	@Override
	public List<EntidadBean> getProveedoresActivos() throws Exception {
		List<EntidadBean> ebl = new LinkedList<EntidadBean>();
		List<Proveedor> cl = ProveedorDAO.getInstancia().findProveedoresActivos();
		for (Proveedor c : cl) {
			ebl.add(c.getBean());
		}
		return ebl;
	}

	@Override
	public void eliminarCliente(EntidadBean cliente) throws Exception {
		Cliente c = ClienteDAO.getInstancia().findById(cliente.getCuil());
		c.setEstado(EEstadoEntidad.inactivo);
		ClienteDAO.getInstancia().update(c);
	}

	@Override
	public void modificarCliente(EntidadBean cliente, String iva,
			String razonSocial) throws Exception {
		Cliente c = ClienteDAO.getInstancia().findById(cliente.getCuil());
		c.setCondicionIVA(iva);
		c.setRazonSocial(razonSocial);
		ClienteDAO.getInstancia().update(c);
	}
	
	@Override
	public void eliminarProveedor(EntidadBean prov) throws Exception {
		Proveedor c = ProveedorDAO.getInstancia().findById(prov.getCuil());
		c.setEstado(EEstadoEntidad.inactivo);
		ProveedorDAO.getInstancia().update(c);
	}

	@Override
	public void modificarProveedor(EntidadBean proveedor,
			String razonSocial) throws Exception {
		Proveedor c = ProveedorDAO.getInstancia().findById(proveedor.getCuil());
		c.setRazonSocial(razonSocial);
		ProveedorDAO.getInstancia().update(c);
	}
	@Override
	public boolean validarODVExistente(Integer sucursal) throws Exception {
		ODV odv = (ODV) GeneralDAO.getInstancia().findById(ODV.class, sucursal);
		if(odv == null)
			return false;
		
		return true;
	}
	
	@Override
	public List<FacturaBean> getFacturas() throws Exception {
		List<FacturaBean> fbl = new LinkedList<FacturaBean>();
		List<Factura> fl = FacturaDAO.getInstancia().findAll(Factura.class);
		for (Factura f : fl) {
			fbl.add(BeanTransformer.toFacturaBean(f));
		}
		return fbl;
	}
	
	@Override
	public List<CotizacionBean> getCotizacionesByOdv(Integer sucursal) throws Exception {
		List<CotizacionBean> cb = new LinkedList<CotizacionBean>();
		for(Cotizacion c :CotizacionDAO.getInstancia().findCotizacionesByOdv(sucursal)){
			cb.add(c.getBean());
		}
		return cb;
	}

}
